home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / glibc-1.09 / glibc-1 / glibc-1.09.1 / inet / rcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-31  |  10.0 KB  |  410 lines

  1. /*
  2.  * Copyright (c) 1983, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #if defined(LIBC_SCCS) && !defined(lint)
  35. static char sccsid[] = "@(#)rcmd.c    8.3 (Berkeley) 3/26/94";
  36. #endif /* LIBC_SCCS and not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/socket.h>
  40. #include <sys/stat.h>
  41.  
  42. #include <netinet/in.h>
  43. #include <arpa/inet.h>
  44.  
  45. #include <signal.h>
  46. #include <fcntl.h>
  47. #include <netdb.h>
  48. #include <unistd.h>
  49. #include <pwd.h>
  50. #include <errno.h>
  51. #include <stdio.h>
  52. #include <ctype.h>
  53. #include <string.h>
  54.  
  55. int    __ivaliduser __P((FILE *, u_long, const char *, const char *));
  56. static int __icheckhost __P((u_long, char *));
  57.  
  58. int
  59. rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
  60.     char **ahost;
  61.     u_short rport;
  62.     const char *locuser, *remuser, *cmd;
  63.     int *fd2p;
  64. {
  65.     struct hostent *hp;
  66.     struct sockaddr_in sin, from;
  67.     fd_set reads;
  68.     long oldmask;
  69.     pid_t pid;
  70.     int s, lport, timo;
  71.     char c;
  72.  
  73.     pid = getpid();
  74.     hp = gethostbyname(*ahost);
  75.     if (hp == NULL) {
  76.         herror(*ahost);
  77.         return (-1);
  78.     }
  79.     *ahost = hp->h_name;
  80.     oldmask = sigblock(sigmask(SIGURG));
  81.     for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
  82.         s = rresvport(&lport);
  83.         if (s < 0) {
  84.             if (errno == EAGAIN)
  85.                 (void)fprintf(stderr,
  86.                     "rcmd: socket: All ports in use\n");
  87.             else
  88.                 (void)fprintf(stderr, "rcmd: socket: %s\n",
  89.                     strerror(errno));
  90.             sigsetmask(oldmask);
  91.             return (-1);
  92.         }
  93.         fcntl(s, F_SETOWN, pid);
  94.         sin.sin_family = hp->h_addrtype;
  95.         bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
  96.         sin.sin_port = rport;
  97.         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  98.             break;
  99.         (void)close(s);
  100.         if (errno == EADDRINUSE) {
  101.             lport--;
  102.             continue;
  103.         }
  104.         if (errno == ECONNREFUSED && timo <= 16) {
  105.             (void)sleep(timo);
  106.             timo *= 2;
  107.             continue;
  108.         }
  109.         if (hp->h_addr_list[1] != NULL) {
  110.             int oerrno = errno;
  111.  
  112.             (void)fprintf(stderr, "connect to address %s: ",
  113.                 inet_ntoa(sin.sin_addr));
  114.             errno = oerrno;
  115.             perror(0);
  116.             hp->h_addr_list++;
  117.             bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
  118.             (void)fprintf(stderr, "Trying %s...\n",
  119.                 inet_ntoa(sin.sin_addr));
  120.             continue;
  121.         }
  122.         (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
  123.         sigsetmask(oldmask);
  124.         return (-1);
  125.     }
  126.     lport--;
  127.     if (fd2p == 0) {
  128.         write(s, "", 1);
  129.         lport = 0;
  130.     } else {
  131.         char num[8];
  132.         int s2 = rresvport(&lport), s3;
  133.         int len = sizeof(from);
  134.  
  135.         if (s2 < 0)
  136.             goto bad;
  137.         listen(s2, 1);
  138.         (void)snprintf(num, sizeof(num), "%d", lport);
  139.         if (write(s, num, strlen(num)+1) != strlen(num)+1) {
  140.             (void)fprintf(stderr,
  141.                 "rcmd: write (setting up stderr): %s\n",
  142.                 strerror(errno));
  143.             (void)close(s2);
  144.             goto bad;
  145.         }
  146.         FD_ZERO(&reads);
  147.         FD_SET(s, &reads);
  148.         FD_SET(s2, &reads);
  149.         errno = 0;
  150.         if (select(1 + (s > s2 ? s : s2), &reads, 0, 0, 0) < 1 ||
  151.             !FD_ISSET(s2, &reads)) {
  152.             if (errno != 0)
  153.                 (void)fprintf(stderr,
  154.                     "rcmd: select (setting up stderr): %s\n",
  155.                     strerror(errno));
  156.             else
  157.                 (void)fprintf(stderr,
  158.                 "select: protocol failure in circuit setup\n");
  159.             (void)close(s2);
  160.             goto bad;
  161.         }
  162.         s3 = accept(s2, (struct sockaddr *)&from, &len);
  163.         (void)close(s2);
  164.         if (s3 < 0) {
  165.             (void)fprintf(stderr,
  166.                 "rcmd: accept: %s\n", strerror(errno));
  167.             lport = 0;
  168.             goto bad;
  169.         }
  170.         *fd2p = s3;
  171.         from.sin_port = ntohs((u_short)from.sin_port);
  172.         if (from.sin_family != AF_INET ||
  173.             from.sin_port >= IPPORT_RESERVED ||
  174.             from.sin_port < IPPORT_RESERVED / 2) {
  175.             (void)fprintf(stderr,
  176.                 "socket: protocol failure in circuit setup.\n");
  177.             goto bad2;
  178.         }
  179.     }
  180.     (void)write(s, locuser, strlen(locuser)+1);
  181.     (void)write(s, remuser, strlen(remuser)+1);
  182.     (void)write(s, cmd, strlen(cmd)+1);
  183.     if (read(s, &c, 1) != 1) {
  184.         (void)fprintf(stderr,
  185.             "rcmd: %s: %s\n", *ahost, strerror(errno));
  186.         goto bad2;
  187.     }
  188.     if (c != 0) {
  189.         while (read(s, &c, 1) == 1) {
  190.             (void)write(STDERR_FILENO, &c, 1);
  191.             if (c == '\n')
  192.                 break;
  193.         }
  194.         goto bad2;
  195.     }
  196.     sigsetmask(oldmask);
  197.     return (s);
  198. bad2:
  199.     if (lport)
  200.         (void)close(*fd2p);
  201. bad:
  202.     (void)close(s);
  203.     sigsetmask(oldmask);
  204.     return (-1);
  205. }
  206.  
  207. int
  208. rresvport(alport)
  209.     int *alport;
  210. {
  211.     struct sockaddr_in sin;
  212.     int s;
  213.  
  214.     sin.sin_family = AF_INET;
  215.     sin.sin_addr.s_addr = INADDR_ANY;
  216.     s = socket(AF_INET, SOCK_STREAM, 0);
  217.     if (s < 0)
  218.         return (-1);
  219.     for (;;) {
  220.         sin.sin_port = htons((u_short)*alport);
  221.         if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  222.             return (s);
  223.         if (errno != EADDRINUSE) {
  224.             (void)close(s);
  225.             return (-1);
  226.         }
  227.         (*alport)--;
  228.         if (*alport == IPPORT_RESERVED/2) {
  229.             (void)close(s);
  230.             errno = EAGAIN;        /* close */
  231.             return (-1);
  232.         }
  233.     }
  234. }
  235.  
  236. int    __check_rhosts_file = 1;
  237. char    *__rcmd_errstr;
  238.  
  239. int
  240. ruserok(rhost, superuser, ruser, luser)
  241.     const char *rhost, *ruser, *luser;
  242.     int superuser;
  243. {
  244.     struct hostent *hp;
  245.     u_long addr;
  246.     char **ap;
  247.  
  248.     if ((hp = gethostbyname(rhost)) == NULL)
  249.         return (-1);
  250.     for (ap = hp->h_addr_list; *ap; ++ap) {
  251.         bcopy(*ap, &addr, sizeof(addr));
  252.         if (iruserok(addr, superuser, ruser, luser) == 0)
  253.             return (0);
  254.     }
  255.     return (-1);
  256. }
  257.  
  258. /*
  259.  * New .rhosts strategy: We are passed an ip address. We spin through
  260.  * hosts.equiv and .rhosts looking for a match. When the .rhosts only
  261.  * has ip addresses, we don't have to trust a nameserver.  When it
  262.  * contains hostnames, we spin through the list of addresses the nameserver
  263.  * gives us and look for a match.
  264.  *
  265.  * Returns 0 if ok, -1 if not ok.
  266.  */
  267. int
  268. iruserok(raddr, superuser, ruser, luser)
  269.     u_long raddr;
  270.     int superuser;
  271.     const char *ruser, *luser;
  272. {
  273.     register char *cp;
  274.     struct stat sbuf;
  275.     struct passwd *pwd;
  276.     FILE *hostf;
  277.     uid_t uid;
  278.     int first;
  279.     char pbuf[MAXPATHLEN];
  280.  
  281.     first = 1;
  282.     hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
  283. again:
  284.     if (hostf) {
  285.         if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
  286.             (void)fclose(hostf);
  287.             return (0);
  288.         }
  289.         (void)fclose(hostf);
  290.     }
  291.     if (first == 1 && (__check_rhosts_file || superuser)) {
  292.         first = 0;
  293.         if ((pwd = getpwnam(luser)) == NULL)
  294.             return (-1);
  295.         (void)strcpy(pbuf, pwd->pw_dir);
  296.         (void)strcat(pbuf, "/.rhosts");
  297.  
  298.         /*
  299.          * Change effective uid while opening .rhosts.  If root and
  300.          * reading an NFS mounted file system, can't read files that
  301.          * are protected read/write owner only.
  302.          */
  303.         uid = geteuid();
  304.         (void)seteuid(pwd->pw_uid);
  305.         hostf = fopen(pbuf, "r");
  306.         (void)seteuid(uid);
  307.  
  308.         if (hostf == NULL)
  309.             return (-1);
  310.         /*
  311.          * If not a regular file, or is owned by someone other than
  312.          * user or root or if writeable by anyone but the owner, quit.
  313.          */
  314.         cp = NULL;
  315.         if (lstat(pbuf, &sbuf) < 0)
  316.             cp = ".rhosts lstat failed";
  317.         else if (!S_ISREG(sbuf.st_mode))
  318.             cp = ".rhosts not regular file";
  319.         else if (fstat(fileno(hostf), &sbuf) < 0)
  320.             cp = ".rhosts fstat failed";
  321.         else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
  322.             cp = "bad .rhosts owner";
  323.         else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
  324.             cp = ".rhosts writeable by other than owner";
  325.         /* If there were any problems, quit. */
  326.         if (cp) {
  327.             __rcmd_errstr = cp;
  328.             (void)fclose(hostf);
  329.             return (-1);
  330.         }
  331.         goto again;
  332.     }
  333.     return (-1);
  334. }
  335.  
  336. /*
  337.  * XXX
  338.  * Don't make static, used by lpd(8).
  339.  *
  340.  * Returns 0 if ok, -1 if not ok.
  341.  */
  342. int
  343. __ivaliduser(hostf, raddr, luser, ruser)
  344.     FILE *hostf;
  345.     u_long raddr;
  346.     const char *luser, *ruser;
  347. {
  348.     register char *user, *p;
  349.     int ch;
  350.     char buf[MAXHOSTNAMELEN + 128];        /* host + login */
  351.  
  352.     while (fgets(buf, sizeof(buf), hostf)) {
  353.         p = buf;
  354.         /* Skip lines that are too long. */
  355.         if (strchr(p, '\n') == NULL) {
  356.             while ((ch = getc(hostf)) != '\n' && ch != EOF);
  357.             continue;
  358.         }
  359.         while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
  360.             *p = isupper(*p) ? tolower(*p) : *p;
  361.             p++;
  362.         }
  363.         if (*p == ' ' || *p == '\t') {
  364.             *p++ = '\0';
  365.             while (*p == ' ' || *p == '\t')
  366.                 p++;
  367.             user = p;
  368.             while (*p != '\n' && *p != ' ' &&
  369.                 *p != '\t' && *p != '\0')
  370.                 p++;
  371.         } else
  372.             user = p;
  373.         *p = '\0';
  374.         if (__icheckhost(raddr, buf) &&
  375.             strcmp(ruser, *user ? user : luser) == 0) {
  376.             return (0);
  377.         }
  378.     }
  379.     return (-1);
  380. }
  381.  
  382. /*
  383.  * Returns "true" if match, 0 if no match.
  384.  */
  385. static int
  386. __icheckhost(raddr, lhost)
  387.     u_long raddr;
  388.     register char *lhost;
  389. {
  390.     register struct hostent *hp;
  391.     register u_long laddr;
  392.     register char **pp;
  393.  
  394.     /* Try for raw ip address first. */
  395.     if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1)
  396.         return (raddr == laddr);
  397.  
  398.     /* Better be a hostname. */
  399.     if ((hp = gethostbyname(lhost)) == NULL)
  400.         return (0);
  401.  
  402.     /* Spin through ip addresses. */
  403.     for (pp = hp->h_addr_list; *pp; ++pp)
  404.         if (!bcmp(&raddr, *pp, sizeof(u_long)))
  405.             return (1);
  406.  
  407.     /* No match. */
  408.     return (0);
  409. }
  410.